package com.hhsjdesign.dynamicui.annoprocessor;

import com.hhsjdesign.dynamicui.annoprocess.*;
import com.squareup.javapoet.*;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;

//注解处理器
//将文件处理在build/generated/kapt/
public class ProcessorJava extends AbstractProcessor {

    Messager messager;
    //用于处理元素
    Elements elementUtils;
    private int processTimes = 0;
    Filer filer;
    public static String PACKAGE_NAME = "SEGI_DYNAMIC_UI";
    public static String FRAMEWORK_NAME = "com.hhsjdesign.dynamicui.generate";
    public static String TAG = "_PROCESS";

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet set = new HashSet<String>();
        set.add(ABusinessBean.class.getCanonicalName());
        set.add(ABusinessCaller.class.getCanonicalName());
        set.add(ABusinessViewHolder.class.getCanonicalName());
        set.add(AWidgetType.class.getCanonicalName());
        set.add(AWidgetProperty.class.getCanonicalName());
        set.add(AWidgetData.class.getCanonicalName());
        set.add(AWidgetItemData.class.getCanonicalName());
        return set;
    }


    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_8;
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        elementUtils = processingEnv.getElementUtils();
        filer = processingEnv.getFiler();
    }


    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        String moduleName = processingEnv.getOptions().get(PACKAGE_NAME);
        processTimes++;
        messager.printMessage(Diagnostic.Kind.WARNING, "正在处理: " + moduleName + "包 第 " + processTimes + " 次");

        if (annotations.isEmpty()) {
            return false;
        }

        //要处理的注解

//        for (TypeElement te : annotations) {
//            for (Element e : roundEnv.getElementsAnnotatedWith(te)) {
//                messager.printMessage(Diagnostic.Kind.OTHER, "Printing: " + e.toString());
//            }
//        }

        //要处理的注解
        Set<? extends Element> beans = roundEnv.getElementsAnnotatedWith(ABusinessBean.class);
        Set<? extends Element> viewHolders = roundEnv.getElementsAnnotatedWith(ABusinessViewHolder.class);
        Set<? extends Element> callers = roundEnv.getElementsAnnotatedWith(ABusinessCaller.class);
        Set<? extends Element> widgetTypes = roundEnv.getElementsAnnotatedWith(AWidgetType.class);
        Set<? extends Element> widgetProperties = roundEnv.getElementsAnnotatedWith(AWidgetProperty.class);
        Set<? extends Element> widgetDataList = roundEnv.getElementsAnnotatedWith(AWidgetData.class);
        Set<? extends Element> widgetItemDataList = roundEnv.getElementsAnnotatedWith(AWidgetItemData.class);

        //打印
        messager.printMessage(Diagnostic.Kind.OTHER, moduleName + "找到的类：");
        for (Element element : beans) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }
        for (Element element : viewHolders) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }
        for (Element element : callers) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }

        for (Element element : widgetTypes) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }

        for (Element element : widgetProperties) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }

        for (Element element : widgetDataList) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }

        for (Element element : widgetItemDataList) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            messager.printMessage(
                    Diagnostic.Kind.OTHER,
                    "Printing: " + packagePath + "." + element.getSimpleName().toString() + ".class"
            );
        }

        messager.printMessage(Diagnostic.Kind.OTHER, moduleName + "找到的类：结束");


        //squareup.javapoet 框架创建类

//        deprecatedBuild(titleTypes, widgetTypes, menuItemTypes);


        //squareup.javapoet 框架创建类
        TypeSpec typeSpec = makeClass(
                moduleName,
                beans, viewHolders, callers, widgetTypes, widgetProperties, widgetDataList, widgetItemDataList
        );

        messager.printMessage(Diagnostic.Kind.NOTE, typeSpec.toString());
        messager.printMessage(Diagnostic.Kind.NOTE, "创建类结束");

        return write2Filter(typeSpec, moduleName);
    }


    private TypeSpec makeClass(
            String moduleName,
            Set<? extends Element>... elementSets) {

        //public class DynamicUIViewMap$$[moduleName]
        TypeSpec.Builder targetClass = TypeSpec
                .classBuilder("DynamicUIMap$$" + (moduleName.replaceAll("-", "").replaceAll("_", "")))
                .addModifiers(Modifier.PUBLIC);
        messager.printMessage(Diagnostic.Kind.NOTE, targetClass.build().toString());


        TypeName classUnbounded = ParameterizedTypeName.get(ClassName.get(Class.class),
                WildcardTypeName.subtypeOf(TypeName.OBJECT));
        TypeName setClass = ParameterizedTypeName.get(Map.class, String.class, Class.class);

        //Map<String,Class<?>>
//        ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
//                ClassName.get(Map.class),
//                ClassName.get(String.class),
//                ParameterizedTypeName.get(
//                        ClassName.get(Class.class),
//                        WildcardTypeName.subtypeOf(TypeName.OBJECT)
//                )
//        );

        //Map<String,String>
        ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
                ClassName.get(Map.class),
                ClassName.get(String.class),
                ClassName.get(String.class)
        );

        MethodSpec.Builder beansType = makeMethod("businessBeanTypeList", inputMapTypeOfRoot, elementSets[0], ABusinessBean.class);
        MethodSpec.Builder viewHoldersType = makeMethod("viewHolderTypeList", inputMapTypeOfRoot, elementSets[1], ABusinessViewHolder.class);
        MethodSpec.Builder callersType = makeMethod("dataCallerTypeList", inputMapTypeOfRoot, elementSets[2], ABusinessCaller.class);
        MethodSpec.Builder widgetType = makeMethod("widgetViewTypeList", inputMapTypeOfRoot, elementSets[3], AWidgetType.class);
        MethodSpec.Builder propertyType = makeMethod("widgetPropertyTypeList", inputMapTypeOfRoot, elementSets[4], AWidgetProperty.class);
        MethodSpec.Builder widgetDataType = makeMethod("widgetDataTypeList", inputMapTypeOfRoot, elementSets[5], AWidgetData.class);
        MethodSpec.Builder widgetItemDataType = makeMethod("widgetItemViewTypeList", inputMapTypeOfRoot, elementSets[6], AWidgetItemData.class);

        return targetClass
                .addAnnotation(ADynamicUI.class)
                .addMethod(beansType.build())
                .addMethod(viewHoldersType.build())
                .addMethod(callersType.build())
                .addMethod(widgetType.build())
                .addMethod(propertyType.build())
                .addMethod(widgetDataType.build())
                .addMethod(widgetItemDataType.build())
                .build();
    }

    private MethodSpec.Builder makeMethod(
            String methodName,
            TypeName returns,
            Set<? extends Element> elements,
            Class<? extends Annotation> type
    ) {
        messager.printMessage(Diagnostic.Kind.NOTE, "创建方法： " + methodName);

        //方法 public static Set<Class> methodNme()
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(methodName)
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(returns);

        //第一行，创建Set<Class> result = new HashSet<Class>();
        methodBuilder.addStatement("$T<$T,$T> result = new $T<>() ", Map.class, String.class, String.class, HashMap.class);
        //循环添加注解类 result.add(package.className.class);
        for (Element element : elements) {
            //获取注解类的包名
            PackageElement packageElement = elementUtils.getPackageOf(element);
            String packagePath = packageElement.getQualifiedName().toString();
            String annoValue = null;
            if (type == ABusinessViewHolder.class) {
//                String[] viewHolder = element.getAnnotation(ABusinessViewHolder.class).value();
//                for (String item : viewHolder) {
//                    methodBuilder.addStatement("result.put(\"" + item + "\"," + packagePath + "." + element.getSimpleName().toString() + ".class)");
//                }
                annoValue = element.getAnnotation(ABusinessViewHolder.class).value();
            }

            if (type == ABusinessCaller.class) {
                annoValue = element.getAnnotation(ABusinessCaller.class).value();
            }

            if (type == ABusinessBean.class) {
                annoValue = element.getAnnotation(ABusinessBean.class).value();
            }

            if (type == AWidgetType.class) {
                annoValue = element.getAnnotation(AWidgetType.class).value();
            }

            if (type == AWidgetProperty.class) {
                annoValue = element.getAnnotation(AWidgetProperty.class).value();
            }

            if (type == AWidgetData.class) {
                annoValue = element.getAnnotation(AWidgetData.class).value();
            }

            if (type == AWidgetItemData.class) {
                annoValue = element.getAnnotation(AWidgetItemData.class).value();
            }
            methodBuilder.addStatement("result.put(\"" + annoValue + "\", \"" + packagePath + "." + element.getSimpleName().toString() + "\")");

        }
        //反悔注解类 return result;
        methodBuilder.addStatement("return result");
//        messager.printMessage(Diagnostic.Kind.NOTE, methodBuilder.build().toString());
        messager.printMessage(Diagnostic.Kind.NOTE, "创建方法结束");
        return methodBuilder;
    }

    private Boolean write2Filter(TypeSpec typeSpec, String moduleName) {
        try {
            //将文件写入然后再执行一次注解处理，创建javafile，并写进filer
            JavaFile.builder(FRAMEWORK_NAME, typeSpec).build().writeTo(filer);
            messager.printMessage(Diagnostic.Kind.NOTE, moduleName);
            messager.printMessage(Diagnostic.Kind.NOTE, TAG + "process end ..."
            );

            //返回true表示 注解处理动作结束
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            messager.printMessage(Diagnostic.Kind.NOTE, TAG + "process error ...");
        }
        messager.printMessage(Diagnostic.Kind.NOTE, "process finish ...");
        return false;
    }

}